package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.apis.wemedia.IWemediaClient;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticleService;
import com.heima.article.vos.HotArticleVo;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.wemedia.pojos.WmChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Calendar;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
@Transactional
public class HotArticleServiceImpl implements HotArticleService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ApArticleMapper apArticleMapper;

    @Autowired
    private IWemediaClient wemediaClient;

    /**
     * 计算热点文章方法
     * 该业务方法是要被定时任务自动调用的
     */
    @Override
    public void computeHotArticle() {

        //查询最近五天的文章
        List<ApArticle> apArticleList = getLast5DayArticleList();
        //计算这些文章的分值并且封装到vo中
        List<HotArticleVo> hotArticleVoList = calcArticleScore(apArticleList);
        //将封装好的vo存到redis中
        cacheArticlesToRedis(hotArticleVoList);

    }

    /**
     * 将封装好的vo存到redis中
     * @param hotArticleVoList
     */
    private void cacheArticlesToRedis(List<HotArticleVo> hotArticleVoList) {
        //根据频道名称缓存
        ResponseResult<List<WmChannel>> channels = wemediaClient.getChannels();
        if(channels.getCode() == 200){
            List<WmChannel> channelList = channels.getData();
            for (WmChannel channel : channelList) {
                //过滤出符合当前频道的文章数据集
                List<HotArticleVo> collect = hotArticleVoList.stream().filter(hotArticleVo ->
                        hotArticleVo.getChannelId().equals(channel.getId())).collect(Collectors.toList());
                //缓存到redis
                cacheToRedisWithChannel(collect, ArticleConstants.HOT_ARTICLE_FIRST_PAGE + channel.getId());
            }
        }
        //为推荐频道缓存
        cacheToRedisWithChannel(hotArticleVoList,ArticleConstants.HOT_ARTICLE_FIRST_PAGE + "__all__");
    }

    /**
     * 缓存对应频道数据到redis
     * @param collect 过滤出来相应频道的vo集合
     * @param key 存储到redis对应的key
     */
    private void cacheToRedisWithChannel(List<HotArticleVo> collect, String key) {
        //按照分值排序+取出前三十条分值最高的文章
        collect = collect.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(30).collect(Collectors.toList());
        //把集合缓存到redis中
        redisTemplate.opsForValue().set(key, JSON.toJSONString(collect));
    }

    /**
     * 为符合要求的文章计算分值并封装到vo中
     * @param apArticleList
     * @return
     */
    private List<HotArticleVo> calcArticleScore(List<ApArticle> apArticleList) {
        //参数校验
        if(apArticleList == null || apArticleList.size() <= 0){
            return null;
        }

        List<HotArticleVo> apArticleVoList = apArticleList.stream().map(apArticle -> {
            HotArticleVo vo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle,vo);
            vo.setScore(calcScore(vo));
            return vo;
        }).collect(Collectors.toList());

        return apArticleVoList;
    }

    /**
     * 计算当前文章分值
     * @param vo
     * @return
     */
    private Integer calcScore(HotArticleVo vo) {
        Integer score = 0;
        if(vo.getViews() != null){
            score += vo.getViews();
        }
        if(vo.getLikes() != null){
            score += vo.getLikes() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if(vo.getComment() != null){
            score += vo.getComment() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if(vo.getCollection() != null){
            score += vo.getCollection() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }

    /**
     * 查询最近5天的文章数据
     * @return
     */
    private List<ApArticle> getLast5DayArticleList() {

        //获取五天前的时间
        Calendar instance = Calendar.getInstance();
        //设置时间为五天前
        instance.set(Calendar.DAY_OF_MONTH,-5);
        //获取时间
        Date time = instance.getTime();

        //查询数据
        return apArticleMapper.findArticleListByLast5days(time);
    }
}
